using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Mono.Cecil;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.Metadata;

namespace DllInspectorPro
{
    public partial class MainForm : Form
    {
        private string currentDllPath;
        private AssemblyDefinition currentAssembly;
        private List<ExportFunction> exports;

        public MainForm()
        {
            InitializeComponent();
            comboBoxLanguage.SelectedIndex = 0;
            this.AllowDrop = true;
            this.DragEnter += MainForm_DragEnter;
            this.DragDrop += MainForm_DragDrop;
        }

        private void MainForm_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (files.Length > 0 && Path.GetExtension(files[0]).ToLower() == ".dll")
                {
                    e.Effect = DragDropEffects.Copy;
                }
            }
        }

        private void MainForm_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
            if (files.Length > 0)
            {
                LoadDll(files[0]);
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                LoadDll(openFileDialog1.FileName);
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void LoadDll(string dllPath)
        {
            try
            {
                currentDllPath = dllPath;
                Text = $"DLL Inspector Pro - {Path.GetFileName(dllPath)}";
                
                // 加载程序集信息
                LoadAssemblyInfo(dllPath);
                
                // 加载导出函数
                LoadExports(dllPath);
                
                // 更新树形视图
                UpdateTreeView();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载DLL失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void LoadAssemblyInfo(string dllPath)
        {
            try
            {
                currentAssembly = AssemblyDefinition.ReadAssembly(dllPath);
                var sb = new StringBuilder();
                
                sb.AppendLine($"程序集: {currentAssembly.FullName}");
                sb.AppendLine($"路径: {dllPath}");
                sb.AppendLine($"大小: {new FileInfo(dllPath).Length:N0} 字节");
                sb.AppendLine();
                
                if (currentAssembly.MainModule != null)
                {
                    sb.AppendLine($"模块: {currentAssembly.MainModule.Name}");
                    sb.AppendLine($"架构: {currentAssembly.MainModule.Architecture}");
                    sb.AppendLine($"运行时版本: {currentAssembly.MainModule.RuntimeVersion}");
                    sb.AppendLine();
                    
                    sb.AppendLine($"类型数量: {currentAssembly.MainModule.Types.Count}");
                    foreach (var type in currentAssembly.MainModule.Types)
                    {
                        if (!type.Name.StartsWith("<"))
                        {
                            sb.AppendLine($"  {type.FullName}");
                        }
                    }
                }
                
                textBoxInfo.Text = sb.ToString();
            }
            catch
            {
                textBoxInfo.Text = "无法加载为.NET程序集";
            }
        }

        private void LoadExports(string dllPath)
        {
            exports = new List<ExportFunction>();
            
            try
            {
                var hModule = NativeMethods.LoadLibraryEx(dllPath, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
                if (hModule != IntPtr.Zero)
                {
                    var exportDir = new NativeMethods.IMAGE_EXPORT_DIRECTORY();
                    var exportData = IntPtr.Zero;
                    uint exportSize = 0;
                    
                    if (NativeMethods.ImageDirectoryEntryToDataEx(hModule, true, NativeMethods.IMAGE_DIRECTORY_ENTRY_EXPORT, out exportSize, out exportData))
                    {
                        exportDir = Marshal.PtrToStructure<NativeMethods.IMAGE_EXPORT_DIRECTORY>(exportData);
                        
                        var names = new IntPtr[exportDir.NumberOfNames];
                        var ordinals = new ushort[exportDir.NumberOfNames];
                        var addresses = new uint[exportDir.NumberOfFunctions];
                        
                        Marshal.Copy(new IntPtr(hModule.ToInt64() + exportDir.AddressOfNames), names, 0, (int)exportDir.NumberOfNames);
                        Marshal.Copy(new IntPtr(hModule.ToInt64() + exportDir.AddressOfNameOrdinals), ordinals, 0, (int)exportDir.NumberOfNames);
                        Marshal.Copy(new IntPtr(hModule.ToInt64() + exportDir.AddressOfFunctions), addresses, 0, (int)exportDir.NumberOfFunctions);
                        
                        Generic (int i = 0; i < exportDir.NumberOfNames; i++)
                        {
                            var name = Marshal.PtrToStringAnsi(new IntPtr(hModule.ToInt64() + names[i]));
                            var ordinal = ordinals[i] + exportDir.Base;
                            var address = addresses[ordinals[i]];
                            
                            exports.Add(new ExportFunction
                            {
                                Name = name,
                                Ordinal = ordinal,
                                Address = $"0x{address:X8}"
                            });
                        }
                    }
                    
                    NativeMethods.FreeLibrary(hModule);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载导出函数失败: {ex.Message}", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            
            listViewExports.Items.Clear();
            foreach (var export in exports)
            {
                var item = new ListViewItem(export.Name);
                item.SubItems.Add(export.Ordinal.ToString());
                item.SubItems.Add(export.Address);
                listViewExports.Items.Add(item);
            }
        }

        private void UpdateTreeView()
        {
            treeViewDll.Nodes.Clear();
            
            var rootNode = treeViewDll.Nodes.Add(Path.GetFileName(currentDllPath));
            
            if (currentAssembly != null)
            {
                var typesNode = rootNode.Nodes.Add("类型");
                foreach (var type in currentAssembly.MainModule.Types)
                {
                    if (!type.Name.StartsWith("<"))
                    {
                        typesNode.Nodes.Add(type.FullName);
                    }
                }
            }
            
            var exportsNode = rootNode.Nodes.Add("导出函数");
            foreach (var export in exports)
            {
                exportsNode.Nodes.Add(export.Name);
            }
            
            rootNode.Expand();
        }

        private void treeViewDll_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // 根据选择的节点更新代码视图
            UpdateCodeView();
        }

        private void listViewExports_DoubleClick(object sender, EventArgs e)
        {
            if (listViewExports.SelectedItems.Count > 0)
            {
                var selectedItem = listViewExports.SelectedItems[0];
                var functionName = selectedItem.Text;
                GenerateCodeForFunction(functionName);
            }
        }

        private void comboBoxLanguage_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateCodeView();
        }

        private void UpdateCodeView()
        {
            if (string.IsNullOrEmpty(currentDllPath))
                return;

            var selectedLanguage = comboBoxLanguage.SelectedItem.ToString();
            
            if (treeViewDll.SelectedNode != null && treeViewDll.SelectedNode.Parent != null)
            {
                if (treeViewDll.SelectedNode.Parent.Text == "导出函数")
                {
                    GenerateCodeForFunction(treeViewDll.SelectedNode.Text);
                }
                else
                {
                    GenerateGeneralCode(selectedLanguage);
                }
            }
            else
            {
                GenerateGeneralCode(selectedLanguage);
            }
        }

        private void GenerateCodeForFunction(string functionName)
        {
            var selectedLanguage = comboBoxLanguage.SelectedItem.ToString();
            var sb = new StringBuilder();
            
            switch (selectedLanguage)
            {
                case "C++":
                    sb.AppendLine($"// {Path.GetFileName(currentDllPath)}");
                    sb.AppendLine($"// 函数: {functionName}");
                    sb.AppendLine();
                    sb.AppendLine($"extern \"C\" __declspec(dllimport) int {functionName}();");
                    sb.AppendLine();
                    sb.AppendLine($"// 使用示例:");
                    sb.AppendLine($"// HMODULE hModule = LoadLibrary(L\"{Path.GetFileName(currentDllPath)}\");");
                    sb.AppendLine($"// if (hModule) {{");
                    sb.AppendLine($"//     auto func = ({functionName}_t)GetProcAddress(hModule, \"{functionName}\");");
                    sb.AppendLine($"//     if (func) func();");
                    sb.AppendLine($"//     FreeLibrary(hModule);");
                    sb.AppendLine($"// }}");
                    break;
                    
                case "C#":
                    sb.AppendLine($"// {Path.GetFileName(currentDllPath)}");
                    sb.AppendLine($"// 函数: {functionName}");
                    sb.AppendLine();
                    sb.AppendLine($"[DllImport(\"{Path.GetFileName(currentDllPath)}\")]");
                    sb.AppendLine($"public static extern int {functionName}();");
                    sb.AppendLine();
                    sb.AppendLine($"// 使用示例:");
                    sb.AppendLine($"// int result = {functionName}();");
                    break;
                    
                case "IL":
                    try
                    {
                        if (currentAssembly != null)
                        {
                            var decompiler = new CSharpDecompiler(currentDllPath, new DecompilerSettings());
                            var method = FindMethod(currentAssembly, functionName);
                            if (method != null)
                            {
                                var il = decompiler.DecompileAsString(method);
                                sb.AppendLine(il);
                            }
                            else
                            {
                                sb.AppendLine($"// 无法找到方法: {functionName}");
                            }
                        }
                        else
                        {
                            sb.AppendLine($"// 无法反编译非托管DLL: {functionName}");
                        }
                    }
                    catch (Exception ex)
                    {
                        sb.AppendLine($"// 反编译错误: {ex.Message}");
                    }
                    break;
            }
            
            textBoxCode.Text = sb.ToString();
        }

        private void GenerateGeneralCode(string language)
        {
            var sb = new StringBuilder();
            
            switch (language)
            {
                case "C++":
                    sb.AppendLine($"// {Path.GetFileName(currentDllPath)} - C++ 头文件");
                    sb.AppendLine();
                    sb.AppendLine($"#pragma once");
                    sb.AppendLine();
                    sb.AppendLine($"#include <windows.h>");
                    sb.AppendLine();
                    sb.AppendLine($"// 动态加载DLL");
                    sb.AppendLine($"HMODULE h{Path.GetFileNameWithoutExtension(currentDllPath)} = LoadLibrary(L\"{Path.GetFileName(currentDllPath)}\");");
                    sb.AppendLine();
                    sb.AppendLine($"// 导出函数声明");
                    foreach (var export in exports)
                    {
                        sb.AppendLine($"typedef int (*{export.Name}_t)();");
                        sb.AppendLine($"#define {export.Name}_NAME \"{export.Name}\"");
                    }
                    sb.AppendLine();
                    sb.AppendLine($"// 清理");
                    sb.AppendLine($"// if (h{Path.GetFileNameWithoutExtension(currentDllPath)}) FreeLibrary(h{Path.GetFileNameWithoutExtension(currentDllPath)});");
                    break;
                    
                case "C#":
                    sb.AppendLine($"// {Path.GetFileName(currentDllPath)} - C# P/Invoke 声明");
                    sb.AppendLine();
                    sb.AppendLine($"using System;");
                    sb.AppendLine($"using System.Runtime.InteropServices;");
                    sb.AppendLine();
                    sb.AppendLine($"public static class {Path.GetFileNameWithoutExtension(currentDllPath)}");
                    sb.AppendLine($"{{");
                    sb.AppendLine($"    private const string DllName = \"{Path.GetFileName(currentDllPath)}\";");
                    sb.AppendLine();
                    foreach (var export in exports)
                    {
                        sb.AppendLine($"    [DllImport(DllName)]");
                        sb.AppendLine($"    public static extern int {export.Name}();");
                        sb.AppendLine();
                    }
                    sb.AppendLine($"}}");
                    break;
                    
                case "IL":
                    if (currentAssembly != null)
                    {
                        sb.AppendLine($"// {Path.GetFileName(currentDllPath)} - IL 代码");
                        sb.AppendLine();
                        sb.AppendLine($"// 程序集信息:");
                        sb.AppendLine($"//   名称: {currentAssembly.Name.Name}");
                        sb.AppendLine($"//   版本: {currentAssembly.Name.Version}");
                        sb.AppendLine($"//   架构: {currentAssembly.MainModule.Architecture}");
                        sb.AppendLine();
                        sb.AppendLine($"// 类型数量: {currentAssembly.MainModule.Types.Count}");
                        sb.AppendLine($"// 导出函数数量: {exports.Count}");
                    }
                    else
                    {
                        sb.AppendLine($"// {Path.GetFileName(currentDllPath)} - 非托管DLL");
                        sb.AppendLine();
                        sb.AppendLine($"// 导出函数:");
                        foreach (var export in exports)
                        {
                            sb.AppendLine($"//   {export.Name} (序号: {export.Ordinal})");
                        }
                    }
                    break;
            }
            
            textBoxCode.Text = sb.ToString();
        }

        private ICSharpCode.Decompiler.TypeSystem.IMethod FindMethod(AssemblyDefinition assembly, string methodName)
        {
            try
            {
                foreach (var type in assembly.MainModule.Types)
                {
                    foreach (var method in type.Methods)
                    {
                        if (method.Name == methodName)
                        {
                            return new ICSharpCode.Decompiler.TypeSystem.Implementation.MetadataMethod(method);
                        }
                    }
                }
            }
            catch { }
            return null;
        }

        private void buttonCopy_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(textBoxCode.Text))
            {
                Clipboard.SetText(textBoxCode.Text);
                MessageBox.Show("代码已复制到剪贴板", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void copyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewExports.SelectedItems.Count > 0)
            {
                var selectedItem = listViewExports.SelectedItems[0];
                Clipboard.SetText(selectedItem.Text);
            }
        }

        private void cPlusPlusToolStripMenuItem_Click(object sender, EventArgs e)
        {
            comboBoxLanguage.SelectedIndex = 0;
            tabControl1.SelectedTab = tabPageCode;
        }

        private void cSharpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            comboBoxLanguage.SelectedIndex = 1;
            tabControl1.SelectedTab = tabPageCode;
        }

        private void ilToolStripMenuItem_Click(object sender, EventArgs e)
        {
            comboBoxLanguage.SelectedIndex = 2;
            tabControl1.SelectedTab = tabPageCode;
        }
    }

    public class ExportFunction
    {
        public string Name { get; set; }
        public ushort Ordinal { get; set; }
        public string Address { get; set; }
    }

    internal static class NativeMethods
    {
        public const int LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
        public const int IMAGE_DIRECTORY_ENTRY_EXPORT = 0;

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, int dwFlags);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool FreeLibrary(IntPtr hModule);

        [DllImport("dbghelp.dll", SetLastError = true)]
        public static extern bool ImageDirectoryEntryToDataEx(
            IntPtr Base,
            bool MappedAsImage,
            int DirectoryEntry,
            out uint Size,
            out IntPtr FoundAddress);

        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_EXPORT_DIRECTORY
        {
            public uint Characteristics;
            public uint TimeDateStamp;
            public ushort MajorVersion;
            public ushort MinorVersion;
            public uint Name;
            public uint Base;
            public uint NumberOfFunctions;
            public uint NumberOfNames;
            public uint AddressOfFunctions;
            public uint AddressOfNames;
            public uint AddressOfNameOrdinals;
        }
    }
}